﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xant.FlowEngine.Interface;

namespace Xant.FlowEngine.Core
{
    public abstract class AbstractProcess : AbstractFlowObject
    {
        #region 变量
        
        /*不再转发活动事件，这样设计会使类维护起来更加困难，尽量保持类的纯净，不属于职责范围内的事不做
        public delegate void ActivityStatusChangedHandler(AbstractActivity activity);
        public ActivityStatusChangedHandler ActivityStatusChanged;
        */
        protected List<AbstractActivity> activities;
        protected List<Transition> transitions;
        #endregion

        #region 属性

        [MaxLength(100)]
        public string Name { get; set; }

        public StartActivity StartActivity
        {
            get
            {
                return activities.Where(p => p.GetType() == typeof(StartActivity)).FirstOrDefault() as StartActivity;
            }
        }

        public EndActivity EndActivity
        {
            get
            {
                return activities.Where(p => p.GetType() == typeof(EndActivity)).FirstOrDefault() as EndActivity;
            }
        }

        /// <summary>
        /// 活动集合
        /// </summary>
        public IReadOnlyList<AbstractActivity> Activities
        {
            get
            {
                return activities.AsReadOnly();
            }
        }

        /// <summary>
        /// 活动变迁集合
        /// </summary>
        public IReadOnlyList<Transition> Transitions
        {
            get
            {
                return transitions.AsReadOnly();
            }
        }

        /// <summary>
        /// 流程创建者
        /// </summary>
        IStaff Creator { get; set; }

        /// <summary>
        /// 流程创建时间
        /// </summary>
        DateTime CreateTime { get; set; }

        #endregion

        #region 构造函数
        public AbstractProcess()
        {
            activities = new List<AbstractActivity>();
            transitions = new List<Transition>();
        }

        public AbstractProcess(string name)
            : this()
        {
            this.Name = name;
        }

        #endregion

        #region 公有方法
        /// <summary>
        /// 添加活动到流程
        /// </summary>
        /// <param name="activity"></param>
        public void AddActivity(AbstractActivity activity)
        {
            if(FindActivity(activity.Code)!=null)
            {
                throw new Exception(string.Format("已经存在编号为{0}的活动，不能添加重号的活动到同一流程中。", activity.Code));
            }
            activity.OwnerProcess = this;
            activity.StatusChanged += activity_StatusChanged;
            this.activities.Add(activity);
        }

        /// <summary>
        /// 添加活动集合到流程
        /// <remarks>
        /// 如果集合中的某个活动编号与流程现有活动重复，则集合中所有活动都不会被添加到流程中
        /// </remarks>
        /// </summary>
        /// <param name="activities">活动集</param>
        public void AddActivities(params AbstractActivity[] activities)
        {
            foreach (var activity in activities)
            {
                if(FindActivity(activity.Code)!=null)
                {
                    throw new Exception(string.Format("已经存在编号为{0}的活动，不能添加重号的活动到同一流程中。", activity.Code));
                }
            }
            foreach (var activity in activities)
            {
                AddActivity(activity);
            }
        }

        /// <summary>
        /// 从流程中删除指定的活动，与该活动相关的迁转将被同时删除
        /// </summary>
        /// <param name="activity"></param>
        public void RemoveActivity(AbstractActivity activity)
        {
            int index = this.activities.IndexOf(activity);
            if (index >= 0)
            {
                //删除与此活动相关的迁转
                foreach (var transition in this.transitions.Where(p => p.From.Equals(activity) || p.To.Equals(activity)))
                {
                    this.transitions.Remove(transition);
                }
                this.activities.RemoveAt(index);
                activity.StatusChanged -= activity_StatusChanged;
            }
        }

        /// <summary>
        /// 从流程中删除指定的一批活动，不存在于流程中的活动将被忽略
        /// </summary>
        /// <param name="activities"></param>
        public void RemoveActivities(IEnumerable<AbstractActivity> activities)
        {
            foreach (var activity in activities)
            {
                RemoveActivity(activity);
            }
        }

        public AbstractActivity FindActivity(Guid id)
        {
            return activities.Where(p => p.Id.Equals(id)).SingleOrDefault();
        }

        public AbstractActivity FindActivity(string code)
        {
            return activities.Where(p => p.Code.Equals(code, StringComparison.CurrentCultureIgnoreCase)).SingleOrDefault();
        }

        /// <summary>
        /// 添加迁转到流程
        /// </summary>
        /// <param name="transition"></param>
        public void AddTransition(Transition transition)
        {
            transitions.Add(transition);
        }

        /// <summary>
        /// 添加迁转到流程
        /// </summary>
        /// <param name="fromActivityCode"></param>
        /// <param name="toActivityCode"></param>
        /// <returns></returns>
        public Transition AddTransition(string fromActivityCode, string toActivityCode)
        {
            var from = FindActivity(fromActivityCode);
            var to = FindActivity(toActivityCode);
            if (from == null || to == null)
            {
                throw new Exception("activity not found!");
            }
            return AddTransition(from, to);
        }

        /// <summary>
        /// 添加迁转到流程
        /// </summary>
        /// <param name="fromActivity"></param>
        /// <param name="toActivity"></param>
        /// <returns></returns>
        public Transition AddTransition(AbstractActivity from, AbstractActivity to)
        {
            if (!activities.Contains(from))
            {
                throw new Exception();
            }
            if (!activities.Contains(to))
            {
                throw new Exception();
            }
            Transition transition = new Transition(from, to);
            transitions.Add(transition);
            return transition;
        }

        #endregion

        #region 事件响应
        protected void activity_StatusChanged(AbstractActivity activity)
        {
        }

        #endregion

        #region 私有/保护方法
        #endregion

    }

}
